package jmu.edu.yjc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jmu.edu.yjc.Utils.SpringContextUtils;
import jmu.edu.yjc.constants.SystemConstants;
import jmu.edu.yjc.domain.ResponseResult;
import jmu.edu.yjc.domain.entity.ScheduleSetting;
import jmu.edu.yjc.domain.vo.PageVo;
import jmu.edu.yjc.job.scheduled.CronTaskRegistrar;
import jmu.edu.yjc.job.scheduled.SchedulingRunnable;
import jmu.edu.yjc.service.ScheduleSettingService;
import jmu.edu.yjc.mapper.ScheduleSettingMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * (ScheduleSetting)表服务实现类
 *
 * @author makejava
 * @since 2023-04-03 23:50:59
 */
@Service("jobService")
public class ScheduleSettingServiceImpl extends ServiceImpl<ScheduleSettingMapper, ScheduleSetting> implements ScheduleSettingService {

    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;
    @Transactional
    @Override
    public ResponseResult addJob(ScheduleSetting job) {
        if(!checkBean(job.getBeanName(), job.getMethodName(), job.getMethodParams())){
            return ResponseResult.errorResult(-1,"bean不存在，或者方法不存在");
        }
        if (SystemConstants.JOB_STATUS_OPEN == job.getJobStatus()){
            SchedulingRunnable task = new SchedulingRunnable(job.getBeanName(), job.getMethodName(),
                    job.getMethodParams());
            cronTaskRegistrar.addCronTask(task, job.getCronExpression());
        }
        save(job);
        return ResponseResult.okResult();
    }
    @Transactional
    @Override
    public ResponseResult updateJob(ScheduleSetting job) {
        if(!checkBean(job.getBeanName(), job.getMethodName(), job.getMethodParams())){
            return ResponseResult.errorResult(-1,"bean不存在，或者方法不存在");
        }
        ScheduleSetting oldJob = getById(job.getJobId());
        SchedulingRunnable oldRunnable = new SchedulingRunnable(oldJob.getBeanName(),oldJob.getMethodName(),
                oldJob.getMethodParams());
        cronTaskRegistrar.removeCronTask(oldRunnable);
        if (SystemConstants.JOB_STATUS_OPEN == job.getJobStatus()) {
            SchedulingRunnable newRunnable = new SchedulingRunnable(job.getBeanName(), job.getMethodName(),
                    job.getMethodParams());
            cronTaskRegistrar.addCronTask(newRunnable, job.getCronExpression());
        }
        updateById(job);
        return ResponseResult.okResult();
    }
    @Transactional
    @Override
    public ResponseResult deleteJob(Long id) {
        ScheduleSetting oldJob = getById(id);
        SchedulingRunnable oldRunnable = new SchedulingRunnable(oldJob.getBeanName(),oldJob.getMethodName(),
                oldJob.getMethodParams());
        removeById(id);
        cronTaskRegistrar.removeCronTask(oldRunnable);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult listJob(Integer pageNum, Integer pageSize, String beanName) {
        LambdaQueryWrapper<ScheduleSetting> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.hasText(beanName),ScheduleSetting::getBeanName,beanName);
        Page<ScheduleSetting> page = new Page<>(pageNum,pageSize);
        page(page,wrapper);
        return ResponseResult.okResult(new PageVo(page.getRecords(),page.getTotal()));
    }
    @Transactional
    @Override
    public ResponseResult updateJobStatus(ScheduleSetting job) {
        // 修改任务状态
        boolean b = updateById(job);
        if(!b) {
            return ResponseResult.errorResult(-1,"修改状态失败");
        }
        SchedulingRunnable task = new SchedulingRunnable(job.getBeanName(),
                job.getMethodName(), job.getMethodParams());
        if (SystemConstants.JOB_STATUS_OPEN == job.getJobStatus()) {
            cronTaskRegistrar.addCronTask(task, job.getCronExpression());
        } else {
            cronTaskRegistrar.removeCronTask(task);
        }
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult executeJob(ScheduleSetting job) {
        Object bean = SpringContextUtils.getBean(job.getBeanName());
        Method method = null;
        try {
            if(StringUtils.hasText(job.getMethodParams())) {
                method = bean.getClass().getDeclaredMethod(job.getMethodName(),String.class);
            } else {
                method = bean.getClass().getDeclaredMethod(job.getMethodName());
            }

            ReflectionUtils.makeAccessible(method);
            if (StringUtils.hasText(job.getMethodParams())) {
                method.invoke(bean, job.getMethodParams());
            } else {
                method.invoke(bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.errorResult(-1,"任务调用失败" + e.getMessage());
        }
        return ResponseResult.okResult();
    }

    private boolean checkBean(String beanName, String methodName , String methodParams) {
        boolean b = true;
        Object bean = SpringContextUtils.getBean(beanName);
        Method method = null;
        try {
            if(StringUtils.hasText(methodParams)) {
                method = bean.getClass().getDeclaredMethod(methodName,String.class);
            } else {
                method = bean.getClass().getDeclaredMethod(methodName);
            }
        } catch (NoSuchMethodException e) {
            b = false;
            e.printStackTrace();
        }
        return b;
    }
}
